-- card: 32474 from stack: in.5 -- bmap block id: 42372 -- flags: 0000 -- background id: 3858 -- name: DragRect ----- HyperTalk script ----- on OpenCard global INITIAL_LOC put the loc of cd btn 1 into line 1 of INITIAL_LOC put the loc of cd btn 2 into line 2 of INITIAL_LOC pass OpenCard end OpenCard on CloseCard global INITIAL_LOC set the loc of cd btn 1 to line 1 of INITIAL_LOC set the loc of cd btn 2 to line 2 of INITIAL_LOC pass CloseCard end CloseCard on hideObjects hide cd btn 1 hide cd btn 2 hide cd fld "label" end hideObjects on showObjects show cd btn 1 show cd btn 2 show cd fld "label" end showObjects -- part 2 (field) -- low flags: 01 -- high flags: 0000 -- rect: left=28 top=171 right=207 bottom=212 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 3 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: label -- part 3 (button) -- low flags: 00 -- high flags: 8004 -- rect: left=22 top=279 right=310 bottom=210 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: DragRect(rect of me, "NoClipping") ----- HyperTalk script ----- on mouseDown put the rect of me into buttonRect put the loc of me into myLoc put DragRect(the rect of me, "noclipping") into locOffset -- -- convert HC window location to local coords put the rect of cd window into windowRect put OffsetRect(-(item 1 of windowRect), -(item 2 of windowRect), windowRect) into windowRect -- -- what will the rect of the button be now? put OffsetRect(item 1 of locOffset, item 2 of locOffset, buttonRect) into buttonRect -- -- make a slightly smaller than actual size rect (small safety -- margin) for the new button so that we can test to see if it -- will end up off-screen if we move it put item 1 of buttonRect + 5 & "," & item 2 of buttonRect + 5 into topLeft put item 3 of buttonRect - 5 & "," & item 4 of buttonRect - 5 into botRight put item 3 of buttonRect - 5 & "," & item 2 of buttonRect + 5 into topRight put item 1 of buttonRect + 5 & "," & item 4 of buttonRect - 5 into botLeft -- -- see if the button was released offscreen if (topLeft is not within windowRect) and (botRight is not within windowRect) and (topRight is not within windowRect) and (botLeft is not within windowRect) then answer "This button can't be moved outside of HC's window." else add item 1 of locOffset to item 1 of myLoc add item 2 of locOffset to item 2 of myLoc set the loc of me to myLoc end if end mouseDown function OffsetRect deltaX, deltaY, origRect -- offset a rectangle, useful for converting between local (within -- HC's card window) and global coordinates add deltaX to item 1 of origRect add deltaX to item 3 of origRect add deltaY to item 2 of origRect add deltaY to item 4 of origRect return origRect end OffsetRect -- part 4 (button) -- low flags: 00 -- high flags: 8004 -- rect: left=44 top=223 right=254 bottom=183 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: DragRect(rect of me) ----- HyperTalk script ----- on mouseDown put the rect of me into buttonRect put the loc of me into myLoc put DragRect(rect of me) into locOffset -- -- convert HC window location to local coords put the rect of cd window into windowRect put OffsetRect(-(item 1 of windowRect), -(item 2 of windowRect), windowRect) into windowRect -- -- what will the rect of the button be now? put OffsetRect(item 1 of locOffset, item 2 of locOffset, buttonRect) into buttonRect -- -- make a slightly smaller than actual size rect (small safety -- margin) for the new button so that we can test to see if it -- will end up off-screen if we move it put item 1 of buttonRect + 5 & "," & item 2 of buttonRect + 5 into topLeft put item 3 of buttonRect - 5 & "," & item 4 of buttonRect - 5 into botRight put item 3 of buttonRect - 5 & "," & item 2 of buttonRect + 5 into topRight put item 1 of buttonRect + 5 & "," & item 4 of buttonRect - 5 into botLeft -- -- see if the button was released offscreen if (topLeft is not within windowRect) and (botRight is not within windowRect) and (topRight is not within windowRect) and (botLeft is not within windowRect) then answer "The button can't be moved outside of HC's window." else add item 1 of locOffset to item 1 of myLoc add item 2 of locOffset to item 2 of myLoc set the loc of me to myLoc end if end mouseDown function OffsetRect deltaX, deltaY, origRect -- offset a rectangle, useful for converting between local (within -- HC's card window) and global coordinates add deltaX to item 1 of origRect add deltaX to item 3 of origRect add deltaY to item 2 of origRect add deltaY to item 4 of origRect return origRect end OffsetRect -- part contents for background part 38 ----- text ----- 12/50 -- part contents for card part 2 ----- text ----- Drag the button below to see an example of DragRect -- part contents for background part 20 ----- text ----- An XFCN which drags a gray rectangle around the screen as the mouse is moved. The XFCN returns the distance between the original rectangle (the XFCN's parameter) and the final rectangle (the point at which the mouse button was released). The XFCN keeps control until the mouse button is released. If the optional second parameter contains the literal string “NOCLIPPING” the rect can be dragged anywhere on the screen, otherwise the rect can not be dragged outside of the rect of the card window. Look at the buttons on the right for examples. Calling syntax : DragRect(objectRect, <“NOCLIPPING”>) OBJECTRECT : the coordinates of the rectangle to be dragged. NOCLIPPING : do not limit dragging to withing the card window (optional) -- part contents for background part 42 ----- text ----- unit DragRect; {drag a gray rectangle around the screen, retun the offset from it's start point. constrain the dragging to } { the area of the card window unless otherwise requested, in which case we limit dragging to the desktop } {} { brought to you by: Anup Murarka Eric Carlson } { ALINK: SKEPTIC ALINK: cyNic } { CIS: 76004,3356 } {} { We are part of the Support Tools Development Group, } { Apple Computer, Inc. } {} { please DO NOT contack Mac DTS for support of this code! } {} { please DO contact the authors for support of this code! } {} { Send comments, bug reports, requests to any of the above } { E-mail addresses or to:} {} { (one of us) } { Apple Computer, Inc. } { 900 E. Hamilton, Ave. } { Campbell, CA 95008 } { M/S 72-L } {} { Copyright: © 1989, 1990 by Apple Computer, Inc., all rights reserved. } {} { written by Eric Carlson } { AppleLink: cyNic } { modification history } { Date Initials Comments } { ---- ------ ----------------------------------------------------- } { 8/26/89 ec first written } { 5/13/90 ec version 1.1, modified to allow dragging outside of HC's widow } {} interface uses HyperXCmd; procedure main (paramPtr: XCmdPtr); implementation function AskedForHelp (paramPtr: XCmdPtr; syntaxMsg: Str255; copyrightMsg: Str255): boolean; {check to see if the user sent a '?' or a '!' as } { the only parameter. if so we will respond with } { the calling syntax or the copyright/version info } { for this external } {} var firstStr: str255; begin askedForHelp := false; if paramPtr^.paramCount = 1 then begin ZeroToPas(paramPtr, paramPtr^.params[1]^, firstStr); { what is the first param? } if firstStr = '?' then begin paramPtr^.returnValue := PasToZero(paramPtr, syntaxMsg); askedForHelp := true end{ asked for help } else if firstStr = '!' then begin paramPtr^.returnValue := PasToZero(paramPtr, copyRightMsg); askedForHelp := true end;{ asked for copyright info } end;{ one parameter passed } end;{ function } function NumberToString (paramPtr: XCmdPtr; num: LONGINT): Str255; { use the toolbox call rather than HC's, implement it as a function } var tempStr: str255; begin NumToString(num, tempStr); NumberToString := tempStr; end; function rectToStr (paramPtr: XCMDPtr; r: Rect): Str255; { convert a rect to a string so that it can be used in callbacks or as the result of an external } var tempStr: Str255; begin with r do begin tempStr := CONCAT(NumberToString(paramPtr, left), ','); tempStr := CONCAT(tempStr, NumberToString(paramPtr, top), ','); tempStr := CONCAT(tempStr, NumberToString(paramPtr, right), ','); tempStr := CONCAT(tempStr, NumberToString(paramPtr, bottom)); end; rectToStr := tempStr; end; function strToRect (paramPtr: XCMDPtr; rectStr: Str255): Rect; { convert a string, as from a callback or a passed parameter, to a rect } var where: Integer; tempRect: rect; begin where := POS(',', rectStr); tempRect.left := StrToNum(paramPtr, COPY(rectStr, 1, where - 1)); DELETE(rectStr, 1, where); where := POS(',', rectStr); tempRect.top := StrToNum(paramPtr, COPY(rectStr, 1, where - 1)); DELETE(rectStr, 1, where); where := POS(',', rectStr); tempRect.right := StrToNum(paramPtr, COPY(rectStr, 1, where - 1)); DELETE(rectStr, 1, where); tempRect.bottom := StrToNum(ParamPtr, rectStr); strToRect := tempRect; end; function HCWindowRect (paramPtr: XCMDPtr): rect; { the rect of HC's card window, in GLOBAL coordinates } var theResult: Handle; rectStr: str255; theLength: INTEGER; begin rectStr := 'the rect of card window'; theResult := EvalExpr(paramPtr, rectStr); if (theResult <> nil) and (paramPtr^.result = noErr) then ZeroToPas(paramPtr, theResult^, rectStr) else rectStr := ''; if (theResult <> nil) then DisposHandle(theResult); HCWindowRect := strToRect(paramPtr, rectStr); end; function TheClickLoc (paramPtr: XCMDPtr): Point; { get the point at which the mouse was last clicked } var theResult: Handle; ptStr: str255; where: Integer; begin ptStr := 'the clickLoc'; theResult := EvalExpr(paramPtr, ptStr);{ where was the mouse clicked? } if (theResult = nil) or (paramPtr^.result <> noErr) then begin theClickLoc.v := 0; theClickLoc.h := 0; end else begin ZeroToPas(paramPtr, theResult^, ptStr); where := POS(',', ptStr); TheClickLoc.h := StrToNum(ParamPtr, COPY(ptStr, 1, where - 1)); DELETE(ptStr, 1, where); TheClickLoc.v := StrToNum(ParamPtr, ptStr); end; if (theResult <> nil) then DisposHandle(theResult); { free up the handle's memory! } end; function GetGrayRgn: rgnhandle; { grab the region handle than represents the desktop } var tempRgn: rgnhandle; deskRgnPtr: ^rgnhandle; begin deskRgnPtr := pointer($9EE); tempRgn := deskRgnPtr^; GetGrayRgn := tempRgn; end; function GrayRgnBBox: rect; { get the rectangle that encloses the desktop } var grayRgn: rgnHandle; tempRect: rect; begin SetRect(tempRect, 0, 0, 0, 0);{ make an empty rect } grayRgn := GetGrayRgn; if grayRgn <> nil then GrayRgnBBox := grayRgn^^.rgnBBox else GrayRgnBBox := tempRect; end; procedure DragRect (paramPtr: XCmdPtr); var itemRect, maxRect: Rect; newX, newY: integer; tempStr, tempY, tempX: Str255; copyRtStr, syntaxStr: str255; startPt: Point; newPt: LongInt; dragRgn, tempRgn: RgnHandle; HCPort: GrafPtr; deskPort: GrafPort; err: OSErr; doClipping: boolean; begin copyRtStr := 'v1.1, © 1989, 1990 Apple Computer, Inc. written by Eric Carlson'; syntaxStr := 'DragRect(objectRect, <“NOCLIPPING”>'; if paramPtr^.paramCount < 1 then begin paramPtr^.returnValue := PasToZero(paramPtr, syntaxStr); exit(DragRect); end; if AskedForHelp(paramPtr, syntaxStr, copyRtStr) then exit(DragRect); ZeroToPas(paramPtr, paramPtr^.params[1]^, tempStr);{ now get the rect of the outline to drag } itemRect := StrToRect(paramPtr, tempStr);{ convert our string to a rect } LocalToGlobal(itemRect.TopLeft);{ convert from HC's coords to global so we can make local to our new port later } LocalToGlobal(itemRect.BotRight); { now create a rect to which the dragging will be confined - note that it is initially in GLOBAL coords } { and must be converted to LOCAL coordinates when we open up a new port } if paramPtr^.paramCount > 1 then ZeroToPas(paramPtr, paramPtr^.params[2]^, tempStr); if EqualString(tempStr, 'NOCLIPPING', false, false) then doClipping := false else doClipping := true; startPt := TheClickLoc(paramPtr);{ start the dragging at the last position clicked } LocalToGlobal(startPt);{ convert to global so we can make local to our new port later } GetPort(HCPort);{ remember HC's port so that we can restore it later } OpenPort(@deskPort);{ create and init a new graf port } err := MemError;{ see if it was successful } if err <> noErr then begin{ error, return no movement as we won't get the chance to drag anything } paramPtr^.returnValue := PasToZero(ParamPtr, concat('0', ',', '0')); exit(DragRect); end; { a newly opened port is set the the same size as the default monitor (IM I-163), thus any drawing will be limited to } { this area. expand the port and it's vis region to encompass the size of the desktop if “NOCLIPPING” was requested } PortSize(maxRect.right - maxRect.left, maxRect.bottom - maxRect.top);{ first the port itself } if not (doClipping) then begin maxRect := GrayRgnBBox;{ allow dragging anywhere on screen by using the smallest rect which describes } { the desktop region as our max rect } CopyRgn(GetGrayRgn, deskPort.visRgn);{ now the new port's visible region } end else begin maxRect := HCWindowRect(paramPtr);{ limit dragging to inside of the card window by using it's rectangle } tempRgn := NewRgn;{ create a new region, empty so far } RectRgn(tempRgn, maxRect);{ make it the size of the card window } CopyRgn(tempRgn, deskPort.visRgn);{ and set the new port's visible region to it } DisposeRgn(tempRgn);{ toss our allocated region! } end; { set up the rect of the item to be dragged } GlobalToLocal(itemRect.TopLeft);{ convert from global coords to those of our new port } GlobalToLocal(itemRect.BotRight); dragRgn := NewRgn;{ create a new region, empty so far } RectRgn(dragRgn, itemRect);{ make it the size of the rect to be dragged } { and the location to start the dragging } GlobalToLocal(startPt);{ convert from global coords to those of our new port } { and the size of the limiting rect } with maxRect do{ convert to local coordinates and inset by 5 pixels on all sides } begin GlobalToLocal(TopLeft); GlobalToLocal(BotRight); top := top + 5; left := left + 5; right := right - 5; bottom := bottom - 5; end; newPt := DragGrayRgn(dragRgn, startPt, maxRect, maxRect, noConstraint, nil); { both words of the resulting point = -32768 ($8000) if the mouse was released outside of the maxRect } if newPt <> $80008000 then begin newX := LoWord(newPt); newY := HiWord(newPt); end else begin{ released 'out of bounds', return no movement } newX := 0; newY := 0; end; DisposeRgn(dragRgn);{ toss our allocated region! } ClosePort(@deskPort); SetPort(HCPort);{ make sure HC has its port back in its old shape } tempX := NumberToString(paramPtr, newX);{ convert the X to a string } tempY := NumberToString(paramPtr, newY);{ and the Y value } paramPtr^.returnValue := PasToZero(ParamPtr, concat(tempX, ',', tempY)); end; procedure main (paramPtr: XCmdPtr); begin DragRect(paramPtr); end; end.